package cn.caplike.demo.nio._2017;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

/**
 * 简介：异步FileChannel
 *
 * @author 李珂 2017年11月22日 下午3:11:22
 */
public class AsynchronousFileChannelTest {

	public static void run1() throws IOException {
		/*
		 * 这种方式是由主线程发起I/O操作并轮询等待结果。
		 * 这里用了java.util.concurrent.Future接口，它的能力是不让当前线程阻塞。
		 * 通过将I/O操作转移到另一线程上，并在完成时返回结果，来达到异步的目的。
		 */
		try (AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(Paths.get("data/filechannel/in.txt"), StandardOpenOption.READ)) {
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			// read的第二个参数指定了channel的起始位置
			Future<Integer> result = inChannel.read(buffer, 0);
			// 一直轮询I/O操作是否完成
			while (!result.isDone()) {
				// 做点别的
			}
			buffer.flip();
			while (buffer.hasRemaining()) {
				System.out.print((char) buffer.get());
			}
		}
	}

	public static void run2() throws IOException {
		/*
		 * asynchronousFileChannel.read(ByteBuffer dst,long position, A attachment, CompletionHandler<Integer,? super A> handler)
		 * 该函数是回调式中的核心函数。
		 * 	1. 首先讲最后一个参数，它的第二个泛型类型和第三个参数类型一致为A。
		 * 		该接口有两个待实现的方法，completed(...)和failed(...) 分别代指完成时和失败时如何操作：
		 * 			completed(Integer result, A attachment)的第一个参数是完成了多少个字节；
		 * 			failed(Throwable exc, A attachment)的第一个参数是引起失败的异常类型；
		 * 	2. A 可以理解为在CompletionHandler的实现外部，要给实现内部什么信息。
		 * 		在下面的代码中，我传的A为buffer，以便实现的内部打印buffer信息,也可以传递String类型等；
		 * 	3.	前两个参数分别为与通道交互的byteBuffer和起始位置；
		 */
		try (AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(Paths.get("data/filechannel/in.txt"), StandardOpenOption.READ)) {
			ByteBuffer buf = ByteBuffer.allocate(1024);

			inChannel.read(buf, 0, buf, new CompletionHandler<Integer, ByteBuffer>() {
				@Override
				public void completed(Integer result, ByteBuffer attachment) {
					System.out.println(result);
					attachment.flip();
					while (attachment.hasRemaining()) {
						System.out.print((char) attachment.get());
					}
				}

				@Override
				public void failed(Throwable exc, ByteBuffer attachment) {
					System.out.println("failed" + exc.getMessage());
				}
			});
		}
		// do something else
	}

}
